/**
 * 拖拽排序列表组件
 */
import React, { useCallback, useRef } from "react";
import { cloneDeep } from "lodash";
import { useDrop, useDrag, DropTargetMonitor, XYCoord, DragSourceMonitor } from "react-dnd";
import "./index.scss";

interface IListItem {
  index: number;
  moveCard: (dragIndex: number, hoverIndex: number) => void;
  id?: string;
  [key: string]: any;
}
const ListItem: React.FC<IListItem> = (props: IListItem) => {
  const ref = useRef<HTMLDivElement>(null);
  const [, drop] = useDrop({
    accept: "card",
    hover: (item: any, monitor: DropTargetMonitor) => {
      if (!ref.current) return;
      const dragIndex = item.index;
      const hoverIndex = props.index;
      if (dragIndex === hoverIndex) return;
      const hoverBoundingRect = ref.current?.getBoundingClientRect();
      const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
      const clientOffset = monitor.getClientOffset();
      const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;
      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) return;
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) return;
      props.moveCard(dragIndex, hoverIndex);
      item.index = hoverIndex;
    }
  })
  const [{ isDragging }, drag] = useDrag({
    type: "card",
    item: {
      id: props.id,
      index: props.index
    },
    collect: (monitor: DragSourceMonitor) => ({
      isDragging: monitor.isDragging()
    })
  })
  drag(drop(ref));
  return <div ref={ref} className="visbar-sort-item" style={{ opacity: isDragging ? 0 : 1 }}>
    { props.children }
  </div>
}


interface IDragSortListProps {
  data: Array<any>;
  renderItem?: (item: any) => React.ReactNode;
  className?: string;
  onChange?: (data: Array<any>) => void;
}
const DragSortList: React.FC<IDragSortListProps> = (props: IDragSortListProps) => {
  const [, drag] = useDrag({
    type: "container"
  });
  const moveCard = useCallback(
    (dragIndex: number, hoverIndex: number) => {
      const newData = cloneDeep(props.data);
      newData.splice(hoverIndex, 0, newData.splice(dragIndex, 1)[0]);
      props.onChange && props.onChange(newData);
    }, [props])
  return <>
    <div ref={drag} className={`visbar-sort-list ${props.className}`}>
      {props.data.map((item, index) => {
        return <ListItem index={index} moveCard={moveCard} key={item.id || index}>
          { props.renderItem ? props.renderItem(item) : item.name }
        </ListItem>
      })}
    </div>
  </>
}

export default DragSortList;